Default( "MapDifficulty", 5 )
Default( "MapHandlesGrenades", 0 )

function GM:NPCsGrenadeThrowing ()
	--print ("ello?")
	if (self.LastNPCThink or 0) + 0.5 > CurTime() then return end
	self.LastNPCThink = CurTime()
	for _,npc in pairs (ents.FindByClass ("npc_combine_s")) do
		if (npc.LastGrenade or 0) + 10 < CurTime() and (npc:GetName() == "combine_grenader" or self.MapHandlesGrenades == 0) then
			local targGen;
			local targGenDist = 12500
			--print (tostring(npc)..":")
			--printd (npc)
			for k,v in pairs (ents.FindByClass ("inc_generator")) do
				if !v:IsDestroyed() then
					--if (v:GetPos() - npc:GetPos()):Length() < 600 and math.random() > 0.8 then
					local dist = (v:GetPos() - npc:GetPos()):Length()
					--printd (v, dist)
					if dist < targGenDist then
						targGenDist = dist
						targGen = v
					end
				end
			end
			
				local LOS,block;
				if targGen and targGen:IsValid() then
					local trc = {
						start = npc:GetShootPos(),
						endpos = targGen:GetPos(), 
						filter = npc
					}
					
					local res = util.TraceEntity(trc, npc)
					if res.Entity == targGen then
						LOS = true
					else
						if IsValid(res.Entity) then
							block = res.Entity
						else
							local res = util.TraceLine(trc)
							if res.Entity then
								block = res.Entity
							end
						end
					end


					--printd (trc.Entity)
					if trc.Entity == targGen then LOS = true else block = trc.Entity end
				end
				
				if LOS and targGenDist <= 600 then
					self:ForceGrenadeAtTarget (npc, targGen, 25)
				elseif not LOS and self.MapHandlesGrenades == 0 then
					if block and block:IsValid() and block:GetClass() == "prop_physics" and (block:GetPos() - npc:GetPos()):Length() < 1200 then
						self:ForceGrenadeAtTarget (npc, block, 25)
					end
				end
				
				--self:ForceGrenadeAtTarget (npc, targGen)
				--print ("\n")
		end
	end
end

GM:AddHook ("Think", "NPCsGrenadeThrowing")

function GM:ForceGrenadeAtTarget (npc, ent, chance)
	if math.random() * 100 > chance then return end
	--printd (npc, "NADE", ent)
	ent:SetName ("ent"..ent:EntIndex())
	npc:Fire ("ThrowGrenadeAtTarget", "ent"..ent:EntIndex(), 0)
	npc.LastGrenade = CurTime()
	if npc:GetModel() == "models/combine_super_soldier.mdl" then
		npc.UseLaser = true
		npc.LaserTargetPos = ent:GetPos() + Vector (0,0,48)
	else
		npc.NextGrenadeType = "inc_grenade"
	end
end

--party with their grenades too
function GM:GrenadeTheft( ent )
	if !IsValid(ent) then return end
	if ( ent:GetClass() != "npc_grenade_frag" ) then return end
	if PRECACHING_NPCS then return end // Disable this when we're just precaching the NPCs, it mucks up.
	
	timer.Simple (0.1, function ()
		if IsValid(ent) then
			local phys = ent:GetPhysicsObject()
			if IsValid(phys) then
				phys:SetMass (50)
			end
		end
	end)
	
	--[[local grenType = "inc_grenade_timedfrag"
	local npc = ent:GetOwner()
	printd ("grenade?", ent, npc)
	if npc.NextGrenadeType then
		grenType = npc.NextGrenadeType
		npc.NextGrenadeType = nil
	end
	gren = ents.Create (grenType)
	gren:SetPos (ent:GetPos())
	gren:SetAngles (ent:GetAngles())
	gren:Spawn ()

	printd ("Try.")
	local phys = gren:GetPhysicsObject()
	if ( phys:IsValid() ) then
		printd ("Success?")
		--pcall(function() // There's no way to check if it's going to error out on us, so we pcall it just in case.
			phys:SetVelocity (ent:GetPhysicsObject():GetVelocity() * 1.2)
			phys:AddAngleVelocity (ent:GetPhysicsObject():GetAngleVelocity())
		--end)
	end
	
	gren:SetOwner (npc)
	--search for the trail
	for k,v in pairs (ents.GetAll()) do
		if v:GetParent() == ent then
			if v:GetClass() == "env_spritetrail" then
				gren.trail = v
				v:SetParent (gren)
			end
		end
	end
	gren:SetTrail (gren.trail)
	ent:Remove ()]]
end
GM:AddHook ("OnEntityCreated", "GrenadeTheft")

--and their combiballs
function GM:BallTheft( ent )
	if !IsValid(ent) then return end
	if ( ent:GetClass() != "prop_combine_ball" ) then return end
	
	local npc = ent:GetOwner()
	if !IsValid(npc) then return end
	if npc.UseLaser and npc.LaserTargetPos then
		
		local src = ent:GetPos() - ent:GetVelocity():GetNormal() * 24
		local wpn = npc:GetActiveWeapon()
		if IsValid(wpn) then
			printd ("got wpn")
			local atc = wpn:GetAttachment (1)
			printd ("got attach @ ", atc.Pos)
			src = atc.Pos
		end
			
		local dir = (npc.LaserTargetPos - src):GetNormal()
		
		--we'll make them use a bloody LASER
		local bullet = {} 
	 	bullet.Num 		= 1
	 	bullet.Src 		= src
		bullet.Dir 		= dir
	 	bullet.Spread 	= Vector (0, 0, 0)
	 	bullet.Tracer	= 1
		bullet.TracerName	= "inc_tooltracer"
		bullet.Force	= 6
	 	bullet.Damage	= 100
			
		npc:FireBullets (bullet)
			
		npc.LaserTargetPos = nil
		npc.UseLaser = false
		
		ent:Remove()
		
		printd (ent, "used")
	end
end
GM:AddHook ("OnEntityCreated", "BallTheft")

--ammo cleaning
local lastAmmoCheck = 0
function GM:HandleDroppedAmmo ()
	if lastAmmoCheck + 1 < CurTime() then
		local items = ents.FindByClass ("item_*")
		table.Add (items, ents.FindByClass ("weapon_frag"))
		for k,v in pairs (items) do
			if v:IsValid() then
				v:Remove()
			end
		end
	end
end

GM:AddHook ("Think", "HandleDroppedAmmo")

function GM:PhysgunOwnsNPCs( ply, ent )
	if ( IsValid( ent ) && ent:IsNPC() && !ent.Dissolving ) then
		if IsValid (ply) and ply:IsPlayer() then
			self:CreditsForNPCKills (ent, ply, ply, 0.1)
		end
		local dissolve = ents.Create( "env_entity_dissolver" )
			dissolve:SetPos( ent:GetPos() )
			
			ent:SetName( tostring( ent ) )
			dissolve:SetKeyValue( "target", ent:GetName() )
			
			dissolve:SetKeyValue( "dissolvetype", "0" )
		dissolve:Spawn()
		dissolve:Fire( "Dissolve", "", 0 )
		dissolve:Fire( "kill", "", 1 )
		
		dissolve:EmitSound( Sound( "NPC_CombineBall.KillImpact" ) )
		ent:Fire( "sethealth", "0", 0 )
		ent.Dissolving = true
	end
end
GM:AddHook( "PhysgunPickup", "PhysgunOwnsNPCs", 1 )

function GM:PrecacheNPCs()
	local classes = {}
	for _, spawner in pairs( ents.FindByClass( "inc_npcspawn" ) ) do
		local class = spawner:GetNPCClass()
		classes[ class ] = true
	end
	
	PRECACHING_NPCS = true
	for class, _ in pairs( classes ) do
		printd( "PRECACHING " .. class )
		local ent = ents.Create( class )
			ent.CacheEnt = true
		ent:Spawn()
		ent:Remove()
	end
	PRECACHING_NPCS = nil
end
GM:AddHook( "InitPostEntity", "PrecacheNPCs" )

function GM:AutoDissolveNPCs()
	if ( self:IsFight() ) then return end
	if ( self:GetRoundNumber() == 0 ) then return end
	
	self:ChatMessage( "Basic shields operational. Core system rebooting in 10 seconds..." )
	
	timer.Simple( 10, function()
		for _, npc in pairs( ents.FindByClass( "npc_*" ) ) do
			timer.Simple( math.random(), function() GAMEMODE:PhysgunOwnsNPCs( nil, npc ) end )
		end
		GAMEMODE:ChatMessage( "Core system online." )
	end )
end
GM:AddHook( "RoundChanged", "AutoDissolveNPCs" )
function GM:NoKillingTheBasesPlease( ply, ent )
	if ( self:GetRoundNumber() == 0 ) then return end
	if ( ( self:GetRoundLength() - self:GetRoundTimer() ) < 15 ) then return false end
end
GM:AddHook( "PhysgunPickup", "NoKillingTheBasesPlease" )

function GM:OnNPCKilled ()
	--this is to kill death notices
	--self:GetDeathNotice():Kill()
end

function GM:NoNPCFriendlyFire(npc, hitgroup, dmginfo) --to stop NPCs damaging each other
	if (dmginfo:GetAttacker():IsNPC()) or (dmginfo:GetInflictor() == "npc_grenade_frag") then dmginfo:ScaleDamage (0) end
end
GM:AddHook( "ScaleNPCDamage", "NoNPCFriendlyFire" )

function GM:ScaleNPCDamage() end
function GM:NPCHeadshots( npc, hitgroup, info )
	// More damage if we're shot in the head 
	if ( hitgroup == HITGROUP_HEAD ) then 
		--info:ScaleDamage( 3 )
	end
end
GM:AddHook( "ScaleNPCDamage", "NPCHeadshots" )
